home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Chat & Communication / Digsby build 37 / digsby_setup.exe / lib / lxml / cssselect.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-13  |  27KB  |  943 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. import re
  5. from lxml import etree
  6. __all__ = [
  7.     'SelectorSyntaxError',
  8.     'ExpressionError',
  9.     'CSSSelector']
  10.  
  11. try:
  12.     _basestring = basestring
  13. except NameError:
  14.     _basestring = str
  15.  
  16.  
  17. class SelectorSyntaxError(SyntaxError):
  18.     pass
  19.  
  20.  
  21. class ExpressionError(RuntimeError):
  22.     pass
  23.  
  24.  
  25. class CSSSelector(etree.XPath):
  26.     
  27.     def __init__(self, css):
  28.         path = css_to_xpath(css)
  29.         etree.XPath.__init__(self, path)
  30.         self.css = css
  31.  
  32.     
  33.     def __repr__(self):
  34.         return '<%s %s for %r>' % (self.__class__.__name__, hex(abs(id(self)))[2:], self.css)
  35.  
  36.  
  37.  
  38. try:
  39.     _unicode = unicode
  40. except NameError:
  41.     _unicode = str
  42.  
  43.  
  44. class _UniToken(_unicode):
  45.     
  46.     def __new__(cls, contents, pos):
  47.         obj = _unicode.__new__(cls, contents)
  48.         obj.pos = pos
  49.         return obj
  50.  
  51.     
  52.     def __repr__(self):
  53.         return '%s(%s, %r)' % (self.__class__.__name__, _unicode.__repr__(self), self.pos)
  54.  
  55.  
  56.  
  57. class Symbol(_UniToken):
  58.     pass
  59.  
  60.  
  61. class String(_UniToken):
  62.     pass
  63.  
  64.  
  65. class Token(_UniToken):
  66.     pass
  67.  
  68.  
  69. class Class(object):
  70.     
  71.     def __init__(self, selector, class_name):
  72.         self.selector = selector
  73.         self.class_name = class_name
  74.  
  75.     
  76.     def __repr__(self):
  77.         return '%s[%r.%s]' % (self.__class__.__name__, self.selector, self.class_name)
  78.  
  79.     
  80.     def xpath(self):
  81.         sel_xpath = self.selector.xpath()
  82.         sel_xpath.add_condition("contains(concat(' ', normalize-space(@class), ' '), %s)" % xpath_repr(' ' + self.class_name + ' '))
  83.         return sel_xpath
  84.  
  85.  
  86.  
  87. class Function(object):
  88.     unsupported = [
  89.         'target',
  90.         'lang',
  91.         'enabled',
  92.         'disabled']
  93.     
  94.     def __init__(self, selector, type, name, expr):
  95.         self.selector = selector
  96.         self.type = type
  97.         self.name = name
  98.         self.expr = expr
  99.  
  100.     
  101.     def __repr__(self):
  102.         return '%s[%r%s%s(%r)]' % (self.__class__.__name__, self.selector, self.type, self.name, self.expr)
  103.  
  104.     
  105.     def xpath(self):
  106.         sel_path = self.selector.xpath()
  107.         if self.name in self.unsupported:
  108.             raise ExpressionError('The psuedo-class %r is not supported' % self.name)
  109.         
  110.         method = '_xpath_' + self.name.replace('-', '_')
  111.         if not hasattr(self, method):
  112.             raise ExpressionError('The psuedo-class %r is unknown' % self.name)
  113.         
  114.         method = getattr(self, method)
  115.         return method(sel_path, self.expr)
  116.  
  117.     
  118.     def _xpath_nth_child(self, xpath, expr, last = False, add_name_test = True):
  119.         (a, b) = parse_series(expr)
  120.         if not a and not b and not last:
  121.             xpath.add_condition('false() and position() = 0')
  122.             return xpath
  123.         
  124.         if add_name_test:
  125.             xpath.add_name_test()
  126.         
  127.         xpath.add_star_prefix()
  128.         if a == 0:
  129.             if last:
  130.                 b = 'last() - %s' % b
  131.             
  132.             xpath.add_condition('position() = %s' % b)
  133.             return xpath
  134.         
  135.         if last:
  136.             a = -a
  137.             b = -b
  138.         
  139.         if b > 0:
  140.             b_neg = str(-b)
  141.         else:
  142.             b_neg = '+%s' % -b
  143.         if a != 1:
  144.             expr = [
  145.                 '(position() %s) mod %s = 0' % (b_neg, a)]
  146.         else:
  147.             expr = []
  148.         if b >= 0:
  149.             expr.append('position() >= %s' % b)
  150.         elif b < 0 and last:
  151.             expr.append('position() < (last() %s)' % b)
  152.         
  153.         expr = ' and '.join(expr)
  154.         if expr:
  155.             xpath.add_condition(expr)
  156.         
  157.         return xpath
  158.  
  159.     
  160.     def _xpath_nth_last_child(self, xpath, expr):
  161.         return self._xpath_nth_child(xpath, expr, last = True)
  162.  
  163.     
  164.     def _xpath_nth_of_type(self, xpath, expr):
  165.         if xpath.element == '*':
  166.             raise NotImplementedError('*:nth-of-type() is not implemented')
  167.         
  168.         return self._xpath_nth_child(xpath, expr, add_name_test = False)
  169.  
  170.     
  171.     def _xpath_nth_last_of_type(self, xpath, expr):
  172.         return self._xpath_nth_child(xpath, expr, last = True, add_name_test = False)
  173.  
  174.     
  175.     def _xpath_contains(self, xpath, expr):
  176.         if isinstance(expr, Element):
  177.             expr = expr._format_element()
  178.         
  179.         xpath.add_condition('contains(css:lower-case(string(.)), %s)' % xpath_repr(expr.lower()))
  180.         return xpath
  181.  
  182.     
  183.     def _xpath_not(self, xpath, expr):
  184.         expr = expr.xpath()
  185.         cond = expr.condition
  186.         xpath.add_condition('not(%s)' % cond)
  187.         return xpath
  188.  
  189.  
  190.  
  191. def _make_lower_case(context, s):
  192.     return s.lower()
  193.  
  194. ns = etree.FunctionNamespace('http://codespeak.net/lxml/css/')
  195. ns.prefix = 'css'
  196. ns['lower-case'] = _make_lower_case
  197.  
  198. class Pseudo(object):
  199.     unsupported = [
  200.         'indeterminate',
  201.         'first-line',
  202.         'first-letter',
  203.         'selection',
  204.         'before',
  205.         'after',
  206.         'link',
  207.         'visited',
  208.         'active',
  209.         'focus',
  210.         'hover']
  211.     
  212.     def __init__(self, element, type, ident):
  213.         self.element = element
  214.         self.type = type
  215.         self.ident = ident
  216.  
  217.     
  218.     def __repr__(self):
  219.         return '%s[%r%s%s]' % (self.__class__.__name__, self.element, self.type, self.ident)
  220.  
  221.     
  222.     def xpath(self):
  223.         el_xpath = self.element.xpath()
  224.         if self.ident in self.unsupported:
  225.             raise ExpressionError('The psuedo-class %r is unsupported' % self.ident)
  226.         
  227.         method = '_xpath_' + self.ident.replace('-', '_')
  228.         if not hasattr(self, method):
  229.             raise ExpressionError('The psuedo-class %r is unknown' % self.ident)
  230.         
  231.         method = getattr(self, method)
  232.         el_xpath = method(el_xpath)
  233.         return el_xpath
  234.  
  235.     
  236.     def _xpath_checked(self, xpath):
  237.         xpath.add_condition("(@selected or @checked) and (name(.) = 'input' or name(.) = 'option')")
  238.         return xpath
  239.  
  240.     
  241.     def _xpath_root(self, xpath):
  242.         raise NotImplementedError
  243.  
  244.     
  245.     def _xpath_first_child(self, xpath):
  246.         xpath.add_star_prefix()
  247.         xpath.add_name_test()
  248.         xpath.add_condition('position() = 1')
  249.         return xpath
  250.  
  251.     
  252.     def _xpath_last_child(self, xpath):
  253.         xpath.add_star_prefix()
  254.         xpath.add_name_test()
  255.         xpath.add_condition('position() = last()')
  256.         return xpath
  257.  
  258.     
  259.     def _xpath_first_of_type(self, xpath):
  260.         if xpath.element == '*':
  261.             raise NotImplementedError('*:first-of-type is not implemented')
  262.         
  263.         xpath.add_star_prefix()
  264.         xpath.add_condition('position() = 1')
  265.         return xpath
  266.  
  267.     
  268.     def _xpath_last_of_type(self, xpath):
  269.         if xpath.element == '*':
  270.             raise NotImplementedError('*:last-of-type is not implemented')
  271.         
  272.         xpath.add_star_prefix()
  273.         xpath.add_condition('position() = last()')
  274.         return xpath
  275.  
  276.     
  277.     def _xpath_only_child(self, xpath):
  278.         xpath.add_name_test()
  279.         xpath.add_star_prefix()
  280.         xpath.add_condition('last() = 1')
  281.         return xpath
  282.  
  283.     
  284.     def _xpath_only_of_type(self, xpath):
  285.         if xpath.element == '*':
  286.             raise NotImplementedError('*:only-of-type is not implemented')
  287.         
  288.         xpath.add_condition('last() = 1')
  289.         return xpath
  290.  
  291.     
  292.     def _xpath_empty(self, xpath):
  293.         xpath.add_condition('not(*) and not(normalize-space())')
  294.         return xpath
  295.  
  296.  
  297.  
  298. class Attrib(object):
  299.     
  300.     def __init__(self, selector, namespace, attrib, operator, value):
  301.         self.selector = selector
  302.         self.namespace = namespace
  303.         self.attrib = attrib
  304.         self.operator = operator
  305.         self.value = value
  306.  
  307.     
  308.     def __repr__(self):
  309.         if self.operator == 'exists':
  310.             return '%s[%r[%s]]' % (self.__class__.__name__, self.selector, self._format_attrib())
  311.         else:
  312.             return '%s[%r[%s %s %r]]' % (self.__class__.__name__, self.selector, self._format_attrib(), self.operator, self.value)
  313.  
  314.     
  315.     def _format_attrib(self):
  316.         if self.namespace == '*':
  317.             return self.attrib
  318.         else:
  319.             return '%s|%s' % (self.namespace, self.attrib)
  320.  
  321.     
  322.     def _xpath_attrib(self):
  323.         if self.namespace == '*':
  324.             return '@' + self.attrib
  325.         else:
  326.             return '@%s:%s' % (self.namespace, self.attrib)
  327.  
  328.     
  329.     def xpath(self):
  330.         path = self.selector.xpath()
  331.         attrib = self._xpath_attrib()
  332.         value = self.value
  333.         if self.operator == 'exists':
  334.             path.add_condition(attrib)
  335.         elif self.operator == '=':
  336.             path.add_condition('%s = %s' % (attrib, xpath_repr(value)))
  337.         elif self.operator == '!=':
  338.             if value:
  339.                 path.add_condition('not(%s) or %s != %s' % (attrib, attrib, xpath_repr(value)))
  340.             else:
  341.                 path.add_condition('%s != %s' % (attrib, xpath_repr(value)))
  342.         elif self.operator == '~=':
  343.             path.add_condition("contains(concat(' ', normalize-space(%s), ' '), %s)" % (attrib, xpath_repr(' ' + value + ' ')))
  344.         elif self.operator == '|=':
  345.             path.add_condition('%s = %s or starts-with(%s, %s)' % (attrib, xpath_repr(value), attrib, xpath_repr(value + '-')))
  346.         elif self.operator == '^=':
  347.             path.add_condition('starts-with(%s, %s)' % (attrib, xpath_repr(value)))
  348.         elif self.operator == '$=':
  349.             path.add_condition('substring(%s, string-length(%s)-%s) = %s' % (attrib, attrib, len(value) - 1, xpath_repr(value)))
  350.         elif self.operator == '*=':
  351.             path.add_condition('contains(%s, %s)' % (attrib, xpath_repr(value)))
  352.         
  353.         return path
  354.  
  355.  
  356.  
  357. class Element(object):
  358.     
  359.     def __init__(self, namespace, element):
  360.         self.namespace = namespace
  361.         self.element = element
  362.  
  363.     
  364.     def __repr__(self):
  365.         return '%s[%s]' % (self.__class__.__name__, self._format_element())
  366.  
  367.     
  368.     def _format_element(self):
  369.         if self.namespace == '*':
  370.             return self.element
  371.         else:
  372.             return '%s|%s' % (self.namespace, self.element)
  373.  
  374.     
  375.     def xpath(self):
  376.         if self.namespace == '*':
  377.             el = self.element.lower()
  378.         else:
  379.             el = '%s:%s' % (self.namespace, self.element)
  380.         return XPathExpr(element = el)
  381.  
  382.  
  383.  
  384. class Hash(object):
  385.     
  386.     def __init__(self, selector, id):
  387.         self.selector = selector
  388.         self.id = id
  389.  
  390.     
  391.     def __repr__(self):
  392.         return '%s[%r#%s]' % (self.__class__.__name__, self.selector, self.id)
  393.  
  394.     
  395.     def xpath(self):
  396.         path = self.selector.xpath()
  397.         path.add_condition('@id = %s' % xpath_repr(self.id))
  398.         return path
  399.  
  400.  
  401.  
  402. class Or(object):
  403.     
  404.     def __init__(self, items):
  405.         self.items = items
  406.  
  407.     
  408.     def __repr__(self):
  409.         return '%s(%r)' % (self.__class__.__name__, self.items)
  410.  
  411.     
  412.     def xpath(self):
  413.         paths = [ item.xpath() for item in self.items ]
  414.         return XPathExprOr(paths)
  415.  
  416.  
  417.  
  418. class CombinedSelector(object):
  419.     _method_mapping = {
  420.         ' ': 'descendant',
  421.         '>': 'child',
  422.         '+': 'direct_adjacent',
  423.         '~': 'indirect_adjacent' }
  424.     
  425.     def __init__(self, selector, combinator, subselector):
  426.         self.selector = selector
  427.         self.combinator = combinator
  428.         self.subselector = subselector
  429.  
  430.     
  431.     def __repr__(self):
  432.         if self.combinator == ' ':
  433.             comb = '<followed>'
  434.         else:
  435.             comb = self.combinator
  436.         return '%s[%r %s %r]' % (self.__class__.__name__, self.selector, comb, self.subselector)
  437.  
  438.     
  439.     def xpath(self):
  440.         if self.combinator not in self._method_mapping:
  441.             raise ExpressionError('Unknown combinator: %r' % self.combinator)
  442.         
  443.         method = '_xpath_' + self._method_mapping[self.combinator]
  444.         method = getattr(self, method)
  445.         path = self.selector.xpath()
  446.         return method(path, self.subselector)
  447.  
  448.     
  449.     def _xpath_descendant(self, xpath, sub):
  450.         xpath.join('/descendant::', sub.xpath())
  451.         return xpath
  452.  
  453.     
  454.     def _xpath_child(self, xpath, sub):
  455.         xpath.join('/', sub.xpath())
  456.         return xpath
  457.  
  458.     
  459.     def _xpath_direct_adjacent(self, xpath, sub):
  460.         xpath.join('/following-sibling::', sub.xpath())
  461.         xpath.add_name_test()
  462.         xpath.add_condition('position() = 1')
  463.         return xpath
  464.  
  465.     
  466.     def _xpath_indirect_adjacent(self, xpath, sub):
  467.         xpath.join('/following-sibling::', sub.xpath())
  468.         return xpath
  469.  
  470.  
  471. _el_re = re.compile('^\\w+\\s*$')
  472. _id_re = re.compile('^(\\w*)#(\\w+)\\s*$')
  473. _class_re = re.compile('^(\\w*)\\.(\\w+)\\s*$')
  474.  
  475. def css_to_xpath(css_expr, prefix = 'descendant-or-self::'):
  476.     if isinstance(css_expr, _basestring):
  477.         match = _el_re.search(css_expr)
  478.         if match is not None:
  479.             return '%s%s' % (prefix, match.group(0).strip())
  480.         
  481.         match = _id_re.search(css_expr)
  482.         if match is not None:
  483.             if not match.group(1):
  484.                 pass
  485.             return "%s%s[@id = '%s']" % (prefix, '*', match.group(2))
  486.         
  487.         match = _class_re.search(css_expr)
  488.         if match is not None:
  489.             if not match.group(1):
  490.                 pass
  491.             return "%s%s[contains(concat(' ', normalize-space(@class), ' '), ' %s ')]" % (prefix, '*', match.group(2))
  492.         
  493.         css_expr = parse(css_expr)
  494.     
  495.     expr = css_expr.xpath()
  496.     if prefix:
  497.         expr.add_prefix(prefix)
  498.     
  499.     return str(expr)
  500.  
  501.  
  502. class XPathExpr(object):
  503.     
  504.     def __init__(self, prefix = None, path = None, element = '*', condition = None, star_prefix = False):
  505.         self.prefix = prefix
  506.         self.path = path
  507.         self.element = element
  508.         self.condition = condition
  509.         self.star_prefix = star_prefix
  510.  
  511.     
  512.     def __str__(self):
  513.         path = ''
  514.         if self.prefix is not None:
  515.             path += str(self.prefix)
  516.         
  517.         if self.path is not None:
  518.             path += str(self.path)
  519.         
  520.         path += str(self.element)
  521.         if self.condition:
  522.             path += '[%s]' % self.condition
  523.         
  524.         return path
  525.  
  526.     
  527.     def __repr__(self):
  528.         return '%s[%s]' % (self.__class__.__name__, self)
  529.  
  530.     
  531.     def add_condition(self, condition):
  532.         if self.condition:
  533.             self.condition = '%s and (%s)' % (self.condition, condition)
  534.         else:
  535.             self.condition = condition
  536.  
  537.     
  538.     def add_path(self, part):
  539.         self.element = part
  540.  
  541.     
  542.     def add_prefix(self, prefix):
  543.         if self.prefix:
  544.             self.prefix = prefix + self.prefix
  545.         else:
  546.             self.prefix = prefix
  547.  
  548.     
  549.     def add_name_test(self):
  550.         if self.element == '*':
  551.             return None
  552.         
  553.         self.add_condition('name() = %s' % xpath_repr(self.element))
  554.         self.element = '*'
  555.  
  556.     
  557.     def add_star_prefix(self):
  558.         if self.path:
  559.             self.path += '*/'
  560.         else:
  561.             self.path = '*/'
  562.         self.star_prefix = True
  563.  
  564.     
  565.     def join(self, combiner, other):
  566.         prefix = str(self)
  567.         prefix += combiner
  568.         path = None + '' if not other.prefix else ''
  569.         if other.star_prefix and path == '*/':
  570.             path = ''
  571.         
  572.         self.prefix = prefix
  573.         self.path = path
  574.         self.element = other.element
  575.         self.condition = other.condition
  576.  
  577.  
  578.  
  579. class XPathExprOr(XPathExpr):
  580.     
  581.     def __init__(self, items, prefix = None):
  582.         for item in items:
  583.             pass
  584.         
  585.         self.items = items
  586.         self.prefix = prefix
  587.  
  588.     
  589.     def __str__(self):
  590.         if not self.prefix:
  591.             pass
  592.         prefix = ''
  593.         return []([ prefix + str(i) for i in self.items ])
  594.  
  595.  
  596.  
  597. def xpath_repr(s):
  598.     if isinstance(s, Element):
  599.         s = s._format_element()
  600.     
  601.     return repr(str(s))
  602.  
  603.  
  604. def parse(string):
  605.     stream = TokenStream(tokenize(string))
  606.     stream.source = string
  607.     
  608.     try:
  609.         return parse_selector_group(stream)
  610.     except SelectorSyntaxError:
  611.         e = sys.exc_info()[1]
  612.         e.args = tuple([
  613.             '%s at %s -> %s' % (e, stream.used, list(stream))])
  614.         raise 
  615.  
  616.  
  617.  
  618. def parse_selector_group(stream):
  619.     result = []
  620.     while None:
  621.         if stream.peek() == ',':
  622.             stream.next()
  623.             continue
  624.         break
  625.         continue
  626.         if len(result) == 1:
  627.             return result[0]
  628.         else:
  629.             return Or(result)
  630.  
  631.  
  632. def parse_selector(stream):
  633.     result = parse_simple_selector(stream)
  634.     while None:
  635.         peek = stream.peek()
  636.         if peek == ',' or peek is None:
  637.             return result
  638.         elif peek in ('+', '>', '~'):
  639.             combinator = stream.next()
  640.         else:
  641.             combinator = ' '
  642.         next_selector = parse_simple_selector(stream)
  643.         result = CombinedSelector(result, combinator, next_selector)
  644.         continue
  645.         return result
  646.  
  647.  
  648. def parse_simple_selector(stream):
  649.     peek = stream.peek()
  650.     if peek != '*' and not isinstance(peek, Symbol):
  651.         element = namespace = '*'
  652.     else:
  653.         next = stream.next()
  654.         if next != '*' and not isinstance(next, Symbol):
  655.             raise SelectorSyntaxError('Expected symbol, got %r' % next)
  656.         
  657.         if stream.peek() == '|':
  658.             namespace = next
  659.             stream.next()
  660.             element = stream.next()
  661.             if element != '*' and not isinstance(next, Symbol):
  662.                 raise SelectorSyntaxError('Expected symbol, got %r' % next)
  663.             
  664.         else:
  665.             namespace = '*'
  666.             element = next
  667.     result = Element(namespace, element)
  668.     has_hash = False
  669.     while None:
  670.         peek = stream.peek()
  671.         if peek == '#':
  672.             if has_hash:
  673.                 break
  674.             
  675.             stream.next()
  676.             result = Hash(result, stream.next())
  677.             has_hash = True
  678.             continue
  679.             continue
  680.         if peek == '.':
  681.             stream.next()
  682.             result = Class(result, stream.next())
  683.             continue
  684.             continue
  685.         if peek == '[':
  686.             stream.next()
  687.             result = parse_attrib(result, stream)
  688.             next = stream.next()
  689.             if not next == ']':
  690.                 raise SelectorSyntaxError('] expected, got %r' % next)
  691.                 continue
  692.             continue
  693.             continue
  694.         if peek == ':' or peek == '::':
  695.             type = stream.next()
  696.             ident = stream.next()
  697.             if not isinstance(ident, Symbol):
  698.                 raise SelectorSyntaxError('Expected symbol, got %r' % ident)
  699.             
  700.             if stream.peek() == '(':
  701.                 stream.next()
  702.                 peek = stream.peek()
  703.                 if isinstance(peek, String):
  704.                     selector = stream.next()
  705.                 elif isinstance(peek, Symbol) and is_int(peek):
  706.                     selector = int(stream.next())
  707.                 else:
  708.                     selector = parse_simple_selector(stream)
  709.                 next = stream.next()
  710.                 if not next == ')':
  711.                     raise SelectorSyntaxError('Expected ), got %r and %r' % (next, selector))
  712.                 
  713.                 result = Function(result, type, ident, selector)
  714.                 continue
  715.             result = Pseudo(result, type, ident)
  716.             continue
  717.             continue
  718.         if peek == ' ':
  719.             stream.next()
  720.         
  721.         break
  722.         continue
  723.         return result
  724.  
  725.  
  726. def is_int(v):
  727.     
  728.     try:
  729.         int(v)
  730.     except ValueError:
  731.         return False
  732.  
  733.     return True
  734.  
  735.  
  736. def parse_attrib(selector, stream):
  737.     attrib = stream.next()
  738.     if stream.peek() == '|':
  739.         namespace = attrib
  740.         stream.next()
  741.         attrib = stream.next()
  742.     else:
  743.         namespace = '*'
  744.     if stream.peek() == ']':
  745.         return Attrib(selector, namespace, attrib, 'exists', None)
  746.     
  747.     op = stream.next()
  748.     if op not in ('^=', '$=', '*=', '=', '~=', '|=', '!='):
  749.         raise SelectorSyntaxError('Operator expected, got %r' % op)
  750.     
  751.     value = stream.next()
  752.     if not isinstance(value, (Symbol, String)):
  753.         raise SelectorSyntaxError('Expected string or symbol, got %r' % value)
  754.     
  755.     return Attrib(selector, namespace, attrib, op, value)
  756.  
  757.  
  758. def parse_series(s):
  759.     if isinstance(s, Element):
  760.         s = s._format_element()
  761.     
  762.     if not s or s == '*':
  763.         return (0, 0)
  764.     
  765.     if isinstance(s, int):
  766.         return (0, s)
  767.     
  768.     if s == 'odd':
  769.         return (2, 1)
  770.     elif s == 'even':
  771.         return (2, 0)
  772.     elif s == 'n':
  773.         return (1, 0)
  774.     
  775.     if 'n' not in s:
  776.         return (0, int(s))
  777.     
  778.     (a, b) = s.split('n', 1)
  779.     if not a:
  780.         a = 1
  781.     elif a == '-' or a == '+':
  782.         a = int(a + '1')
  783.     else:
  784.         a = int(a)
  785.     if not b:
  786.         b = 0
  787.     elif b == '-' or b == '+':
  788.         b = int(b + '1')
  789.     else:
  790.         b = int(b)
  791.     return (a, b)
  792.  
  793. _whitespace_re = re.compile('\\s+')
  794. _comment_re = re.compile('/\\*.*?\\*/', re.S)
  795. _count_re = re.compile('[+-]?\\d*n(?:[+-]\\d+)?')
  796.  
  797. def tokenize(s):
  798.     pos = 0
  799.     s = _comment_re.sub('', s)
  800.     while None:
  801.         match = _whitespace_re.match(s, pos = pos)
  802.         if match:
  803.             preceding_whitespace_pos = pos
  804.             pos = match.end()
  805.         else:
  806.             preceding_whitespace_pos = 0
  807.         if pos >= len(s):
  808.             return None
  809.         
  810.         match = _count_re.match(s, pos = pos)
  811.         if match and match.group() != 'n':
  812.             sym = s[pos:match.end()]
  813.             yield Symbol(sym, pos)
  814.             pos = match.end()
  815.             continue
  816.         
  817.         c = s[pos]
  818.         c2 = s[pos:pos + 2]
  819.         if c2 in ('~=', '|=', '^=', '$=', '*=', '::', '!='):
  820.             yield Token(c2, pos)
  821.             pos += 2
  822.             continue
  823.         
  824.         if c in '>+~,.*=[]()|:#':
  825.             if c in '.#' and preceding_whitespace_pos > 0:
  826.                 yield Token(' ', preceding_whitespace_pos)
  827.             
  828.             yield Token(c, pos)
  829.             pos += 1
  830.             continue
  831.         
  832.         if c == '"' or c == "'":
  833.             old_pos = pos
  834.             (sym, pos) = tokenize_escaped_string(s, pos)
  835.             yield String(sym, old_pos)
  836.             continue
  837.         
  838.         old_pos = pos
  839.         (sym, pos) = tokenize_symbol(s, pos)
  840.         yield Symbol(sym, old_pos)
  841.         continue
  842.         continue
  843.         return None
  844.  
  845.  
  846. def tokenize_escaped_string(s, pos):
  847.     quote = s[pos]
  848.     pos = pos + 1
  849.     start = pos
  850.     while None:
  851.         next = s.find(quote, pos)
  852.         if next == -1:
  853.             raise SelectorSyntaxError('Expected closing %s for string in: %r' % (quote, s[start:]))
  854.         
  855.         result = s[start:next]
  856.         
  857.         try:
  858.             result = result.encode('ASCII', 'backslashreplace').decode('unicode_escape')
  859.         except UnicodeDecodeError:
  860.             pos = next + 1
  861.             continue
  862.  
  863.         return (result, next + 1)
  864.         continue
  865.         return None
  866.  
  867. _illegal_symbol = re.compile('[^\\w\\\\-]', re.UNICODE)
  868.  
  869. def tokenize_symbol(s, pos):
  870.     start = pos
  871.     match = _illegal_symbol.search(s, pos = pos)
  872.     if not match:
  873.         return (s[start:], len(s))
  874.     
  875.     if match.start() == pos:
  876.         pass
  877.     
  878.     if not match:
  879.         result = s[start:]
  880.         pos = len(s)
  881.     else:
  882.         result = s[start:match.start()]
  883.         pos = match.start()
  884.     
  885.     try:
  886.         result = result.encode('ASCII', 'backslashreplace').decode('unicode_escape')
  887.     except UnicodeDecodeError:
  888.         e = sys.exc_info()[1]
  889.         raise SelectorSyntaxError('Bad symbol %r: %s' % (result, e))
  890.  
  891.     return (result, pos)
  892.  
  893.  
  894. class TokenStream(object):
  895.     
  896.     def __init__(self, tokens, source = None):
  897.         self.used = []
  898.         self.tokens = iter(tokens)
  899.         self.source = source
  900.         self.peeked = None
  901.         self._peeking = False
  902.         
  903.         try:
  904.             self.next_token = self.tokens.next
  905.         except AttributeError:
  906.             self.next_token = self.tokens.__next__
  907.  
  908.  
  909.     
  910.     def next(self):
  911.         if self._peeking:
  912.             self._peeking = False
  913.             self.used.append(self.peeked)
  914.             return self.peeked
  915.         else:
  916.             
  917.             try:
  918.                 next = self.next_token()
  919.                 self.used.append(next)
  920.                 return next
  921.             except StopIteration:
  922.                 return None
  923.  
  924.  
  925.     
  926.     def __iter__(self):
  927.         return iter(self.next, None)
  928.  
  929.     
  930.     def peek(self):
  931.         if not self._peeking:
  932.             
  933.             try:
  934.                 self.peeked = self.next_token()
  935.             except StopIteration:
  936.                 return None
  937.  
  938.             self._peeking = True
  939.         
  940.         return self.peeked
  941.  
  942.  
  943.